﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using NetCore;

namespace NetCore.EF
{
    public class EFEntityFactory
    {
        private EFRepository _dbFactory;
        public EFEntityFactory(EFRepository dbFactory)
        {
            _dbFactory = dbFactory;
        }
        #region update
        public bool Update<TEntity>(TEntity entity) where TEntity : class, new()
        {
            if (entity == null)
                throw new Exception("Entity is null");
            _dbFactory.Current.ChangeTracker.AutoDetectChangesEnabled = false;
            EntityDbFactory dbFactory = new EntityDbFactory(entity.GetType());
            bool flag = false;
            try
            {
                if (_dbFactory.Current.Entry<TEntity>(entity).State == EntityState.Detached)
                {

                }
                SetLastModify(entity, dbFactory);
                _dbFactory.Current.Attach<TEntity>(entity);
                if (this.Update<TEntity>(entity, dbFactory))
                {
                    
                    flag = _dbFactory.Current.SaveChanges() > 0;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                _dbFactory.Current.ChangeTracker.AutoDetectChangesEnabled = true;
            }
            if (flag)
            {
                EntityDbFactory action = new EntityDbFactory(typeof(TEntity));
                action.CacheMerge(entity);
            }

            return flag;
        }
        private void SetLastModify(object entity, EntityDbFactory dbFactory)
        {
            if (entity != null && entity is EntityBase)
            {
                var baseEntity = entity as EntityBase;
                if (baseEntity.UpdateField.Count >= 1)
                {
                    if (dbFactory.EntityMap.Table != null && dbFactory.EntityMap.Table.IsLastModify)
                    {
                        baseEntity.LastModifyUserId = ApplicationEnvironments.DefaultSession.UserId;
                        baseEntity.LastModifyDate = DateTime.Now;
                    }
                }
            }
        }
        private bool Update<TEntity>(TEntity entity, EntityDbFactory dbFactory) where TEntity : class, new()
        {
         
           // _dbFactory.Current.Attach<TEntity>(entity);
            if (entity != null && entity is EntityBase)
            {

                var baseEntity = entity as EntityBase;
                if (baseEntity.UpdateField.Count >= 1)
                {
                    
                    var properties = _dbFactory.Current.Entry<TEntity>(entity).Properties;
                    foreach (var field in properties)
                    {
                        if (dbFactory.EntityMap.PrimaryKey== field.Metadata.PropertyInfo.Name)
                        {
                            continue;
                        }
                        field.IsModified = false;
                        int index = baseEntity.UpdateField.FindIndex(x => x.Contains(field.Metadata.PropertyInfo.Name));
                        field.IsModified = index >= 0;
                    }
                }
            }
            return true;
        }
        public bool Update<TEntity>(List<TEntity> entities) where TEntity : class, new()
        {
            if (entities == null || entities.Count <= 0)
            {
                throw new Exception("Entity is null");
            }
            _dbFactory.Current.ChangeTracker.AutoDetectChangesEnabled = false;
            EntityDbFactory dbFactory = new EntityDbFactory(typeof(TEntity));
            bool flag = false;
            try
            {
                foreach (var entity in entities)
                {
                    SetLastModify(entity, dbFactory);
                }
                _dbFactory.Current.AttachRange(entities);
                foreach (var entity in entities)
                {
                    this.Update<TEntity>(entity);
                }
              
                flag = _dbFactory.Current.SaveChanges() > 0;
            }
            catch (Exception)
            {

            }
            finally
            {
                _dbFactory.Current.ChangeTracker.AutoDetectChangesEnabled = true;
            }
            
            return flag;


        }


        #endregion

        #region delete
        public bool Delete<TEntity>(TEntity entity) where TEntity : class, new()
        {
            if (entity == null)
                throw new Exception("Entity is null");
            _dbFactory.Current.ChangeTracker.AutoDetectChangesEnabled = false;
            bool flag = false;
            try
            {
                EntityDbFactory dbFactory = new EntityDbFactory(typeof(TEntity));
                if (dbFactory != null && dbFactory.EntityMap.Table.IsDeleted)
                {
                    var baseEntity = entity as EntityBase;
                    _dbFactory.Current.Attach<TEntity>(entity);
                    baseEntity.IsDeleted = true;
                    this.Update<TEntity>(entity, dbFactory);
                    flag = _dbFactory.Current.SaveChanges() > 0;
                }
                if (!flag)
                {
                    _dbFactory.Current.Remove<TEntity>(entity);
                    EntityDbFactory action = new EntityDbFactory(entity.GetType());
                    action.RemoveCacheEntity(typeof(TEntity), new object[] { action.GetPrimaryId(entity) });
                    flag = _dbFactory.Current.SaveChanges() > 0;
                }
            }
            catch (Exception)
            {

            }
            finally
            {
                _dbFactory.Current.ChangeTracker.AutoDetectChangesEnabled = true;
            }
            return flag;
         
        }
        public bool Delete(string hql)  
        {
           return _dbFactory.Current.Database.ExecuteSqlCommand(hql)>0;
          

        }
        public bool Delete<TEntity>(List<TEntity> entities) where TEntity : class, new()
        {
            if (entities == null)
                throw new Exception("Entity is null");
            _dbFactory.Current.ChangeTracker.AutoDetectChangesEnabled = false;
            bool flag = false;
            try
            {
                EntityDbFactory dbFactory = new EntityDbFactory(typeof(TEntity));
                if (dbFactory != null && dbFactory.EntityMap.Table.IsDeleted)
                {
                    _dbFactory.Current.AttachRange(entities);
                    foreach (var entity in entities)
                    {
                        var baseEntity = entity as EntityBase;
                        baseEntity.IsDeleted = true;
                        this.Update<TEntity>(entity, dbFactory);
                    }
                    flag= _dbFactory.Current.SaveChanges() > 0;
                }
                if (!flag)
                {
                    _dbFactory.Current.RemoveRange(entities);
                    flag = _dbFactory.Current.SaveChanges() > 0;
                }
            }
            catch (Exception)
            {

            }
            finally
            {
                _dbFactory.Current.ChangeTracker.AutoDetectChangesEnabled = true;
            }
            return flag;

        }
        #endregion
        #region Insert
        public bool Insert<TEntity>(TEntity entity)where TEntity:class,new()
        {
            if (entity == null)
                throw new Exception("Entity is null");
            var table = this.GetTableAttribute(entity.GetType());
            if (table != null)
            {
                var baseEntity = entity as EntityBase;
                if (table.IsCreated)
                {
                    baseEntity.CreateBy = ApplicationEnvironments.DefaultSession.UserId;
                    baseEntity.CreateDate = DateTime.Now;
                }
                if (table.IsLastModify)
                {
                    baseEntity.LastModifyUserId = ApplicationEnvironments.DefaultSession.UserId;
                    baseEntity.LastModifyDate = DateTime.Now;
                }
            }
            
            _dbFactory.Current.Add<TEntity>(entity);
            return _dbFactory.Current.SaveChanges() > 0;
        }

        public bool Insert<TEntity>(List<TEntity> entities) where TEntity : class, new()
        {
            if (entities == null|| entities.Count<=0)
                throw new Exception("Entity is null");
            var table = this.GetTableAttribute(typeof(TEntity));
            if (table != null)
            {
                foreach (var entity in entities)
                {
                    var baseEntity = entity as EntityBase;
                    if (table.IsCreated)
                    {
                        baseEntity.CreateBy = ApplicationEnvironments.DefaultSession.UserId;
                        baseEntity.CreateDate = DateTime.Now;
                    }
                    if (table.IsLastModify)
                    {
                        baseEntity.LastModifyUserId = ApplicationEnvironments.DefaultSession.UserId;
                        baseEntity.LastModifyDate = DateTime.Now;
                    }
                }
                
            }
            _dbFactory.Current.AddRange(entities);
            return _dbFactory.Current.SaveChanges() > 0;
        }
        #endregion
        private TableAttribute GetTableAttribute(Type type)
        {
           return (TableAttribute)type.GetCustomAttributes(typeof(TableAttribute), true).FirstOrDefault();
        }
    }
}
